using System.Collections.Generic;
using System.Diagnostics;
using FishFillets.Data.Helpers;
using FishFillets.Data.levels;
using FishFillets.Model;
using FishFillets.Model.GameItems;

namespace FishFillets.ObjectLogic
{
    public class GameController
    {
        private readonly IGameView gameView;
        private readonly ILevelAgent agent = new LevelAgent();

        private readonly MapManager mapManager;
        private readonly LevelManager levelManager;
        public readonly DialogManager dialogManager;

        private LevelRef currentLevel;
        public BaseLevelScript levelScript;

        public static GameController Instance
        {
            get { return instance; }
        }
        private static GameController instance;

        public Map Map
        {
            get { return mapManager.Map; }
        }

        public Level Level
        {
            get { return levelManager.Level; }
        }

        /// <summary>
        /// Current playing music track.
        /// </summary>
        public string MusicTrack { get; set; }

        /// <summary>
        /// Dialog buffer user for playing songs.
        /// </summary>
        //public Queue<Dialog> DialogBuffer { get; set; }

        public GameController(IGameView gameView)
        {
            instance = this;
            // use dependency injection to add reference to the Game object
            this.gameView = gameView;

            // load the core Map manager
            mapManager = new MapManager();
            levelManager = new LevelManager();
            dialogManager = new DialogManager();
            ItemScriptExtension.agent = agent;

            LoadSettings();

            gameView.ShowMap(Map);
        }

        /// <summary>
        /// TODO Load setting from previous game instance.
        /// Also save settingsd when game is ending.
        /// </summary>
        private void LoadSettings()
        {
            Settings.EffectVolume = 0.75f;
            Settings.TalkVolume = 0.75f;
            Settings.MusicVolume = 0.1f;
            Settings.Subtitles = "cs";
        }

        #region ----- Game wide events -----------------------------------

        public void LoadLevel(LevelRef levelRef)
        {
            currentLevel = levelRef;

            // Load the level using mapManager
            BaseLevelScript baseLevelScript = mapManager.LoadLevel(currentLevel.Name, agent);
            // if this level exists
            if (baseLevelScript == null) return;

            levelScript = baseLevelScript;
            Level level = levelScript.models();

            // remove map from drawing context
            gameView.HideMap();

            // load the level into level manager
            levelManager.LoadLevel(level);

            // load level scripts
            levelScript.prog_init();

            // create level game component
            gameView.ShowLevel(level);
        }

        public void RestartLevel()
        {
            if (Level == null) return;

            // destroy and remove level from drawing context
            gameView.HideLevel();

            // unload the level from level manager
            levelManager.UnloadLevel();

            // Load the level using mapManager
            BaseLevelScript baseLevelScript = mapManager.LoadLevel(currentLevel.Name, agent);
            // if this level exists
            // level must exist
            Debug.Assert(baseLevelScript != null);

            levelScript = baseLevelScript;
            Level level = levelScript.models();

            // load the level into level manager
            levelManager.LoadLevel(level);

            // load level scripts
            levelScript.prog_init();

            // create level game component
            gameView.ShowLevel(level);
        }

        public void AbortLevel()
        {
            if (Level == null) return;

            // destroy and remove level from drawing context
            gameView.HideLevel();

            // unload the level from level manager
            levelManager.UnloadLevel();

            // show Map component
            gameView.ShowMap(Map);
        }

        public void ExitGame()
        {
            // TODO save and other stuff
        }

        public void PlayMusic(string name)
        {
            MusicTrack = name;
        }

        #endregion

        #region ----- Level wide events ----------------------------------

        public bool Move(Direction dir)
        {
            if (Level == null) return false;

            return levelManager.Move(dir);
        }

        public void SwitchPlayer()
        {
            if (Level == null) return;

            levelManager.SwitchPlayer();
        }

        public void SelectPlayer(Fish fish)
        {
            if (Level == null) return;

            levelManager.Fish = fish;
        }

        #endregion
    }
}
